#include "ShadowRender.h"
#include "ShadowMap.h"
#include "RenderItemManager.h"
#include "Game.h"
#include "DepthEffect.h"
#include "ShadowEffect.h"
#include "BlurRender.h"

ShadowRender::ShadowRender()
{

}

ShadowRender::ShadowRender(const ShadowRender&)
{

}

ShadowRender::~ShadowRender()
{

}

void ShadowRender::Initialize()
{
	mWidth = 512;
	mHeight = 512;

	mCDirect3D = CDirect3D::Instance();
	mDeviceContext = mCDirect3D->GetDeviceContext();
	mDevice = mCDirect3D->GetDevice();
	CreateTexture();
	mCDirect3D->CreateDepthBuffer(mWidth, mHeight, &mTextureDepthBuffer, &mStencilView);


	D3D11_RENDER_TARGET_VIEW_DESC renderTargetDesc;
	renderTargetDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
	renderTargetDesc.ViewDimension = D3D11_RTV_DIMENSION::D3D11_RTV_DIMENSION_TEXTURE2D;
	renderTargetDesc.Texture2D.MipSlice = 0;

	HRESULT result;
	result = mDevice->CreateRenderTargetView(mTextureRender, &renderTargetDesc, &mRenderTargetView);

	if(FAILED(result))
	{
		return;
	}

	D3D11_SHADER_RESOURCE_VIEW_DESC  shaderResourceViewDesc;
	// Setup the description of the shader resource view.
	shaderResourceViewDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
	shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
	shaderResourceViewDesc.Texture2D.MipLevels = 1;

	result = CDirect3D::Instance()->GetDevice()->CreateShaderResourceView(mTextureRender,&shaderResourceViewDesc,&mTextureRessource);

	mViewport.Width = (float)mWidth;
	mViewport.Height = (float)mHeight;
	mViewport.MinDepth = 0.0f;
	mViewport.MaxDepth = 1.0f;
	mViewport.TopLeftX = 0.0f;
	mViewport.TopLeftY = 0.0f;

	mShadowMap = new ShadowMap();
	mShadowMap->Initialize();
	mShadowLargeMap = new ShadowMap();
	mShadowLargeMap->Initialize();

	mDepthEffect = new DepthEffect();
	mDepthEffect->Initialize();
	mShadowEffect = new ShadowEffect();
	mShadowEffect->Initialize();

	XMStoreFloat4x4(&mLightProjectionMatrix, XMMatrixOrthographicLH((float)40, (float)40, 1, 100));
	XMStoreFloat4x4(&mLightLargeProjectionMatrix, XMMatrixOrthographicLH((float)100, (float)100, 1, 100));

	mBlurRender = new BlurRender();
	mBlurRender->Initialize();
	mBlurRender->SetTextureToBlur(mTextureRessource);
}

void ShadowRender::Update()
{

}

void ShadowRender::ComputeLightMatrix()
{
	XMFLOAT3 cameraPosition = Game::Instance()->GetCamera()->GetPosition();
	XMVECTOR vectorCameraPosition = XMLoadFloat3(&cameraPosition);
	XMFLOAT3 cameraOrientation = Game::Instance()->GetCamera()->GetVectorOrientation();
	//cameraOrientation = XMFLOAT3(cameraOrientation.x, cameraPosition.y, cameraOrientation.z);
	XMVECTOR vectorCameraOrientation = XMLoadFloat3(&cameraOrientation);

	XMFLOAT3 l = Game::Instance()->GetLightOrientation();
	XMVECTOR vectorLightOrientation = XMLoadFloat3(&l);
	XMVECTOR vectorLightPosition = (vectorCameraPosition + (vectorCameraOrientation * 5)) + (vectorLightOrientation * -20);
	XMVECTOR vectorLightTargetPosition = (vectorCameraPosition + (vectorCameraOrientation * 5));
	XMVECTOR vectorUp = XMLoadFloat3(&XMFLOAT3(0,1,0));
	XMStoreFloat4x4(&mLightViewMatrix, XMMatrixLookAtLH(vectorLightPosition, vectorLightTargetPosition, vectorUp));

	vectorLightPosition = (vectorCameraPosition + (vectorCameraOrientation * 25)) + (vectorLightOrientation * -20);
	vectorLightTargetPosition = (vectorCameraPosition + (vectorCameraOrientation * 25));
	XMStoreFloat4x4(&mLightLargeViewMatrix, XMMatrixLookAtLH(vectorLightPosition, vectorLightTargetPosition, vectorUp));
}

void ShadowRender::Render()
{
	ComputeLightMatrix();

	mShadowMap->Render(&mLightViewMatrix, &mLightProjectionMatrix);
	mShadowLargeMap->Render(&mLightLargeViewMatrix, &mLightLargeProjectionMatrix);

	float color[4];

	// Setup the color to clear the buffer to.
	color[0] = 1.f;
	color[1] = 1.f;
	color[2] = 1.f;
	color[3] = 1.f;

	mDeviceContext->OMSetRenderTargets(1, &mRenderTargetView, mStencilView);
	mDeviceContext->RSSetViewports(1, &mViewport);
	mDeviceContext->ClearRenderTargetView(mRenderTargetView, color);
	mDeviceContext->ClearDepthStencilView(mStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);

	mShadowEffect->SetDepthTexture(mShadowMap->GetTexture());
	mShadowEffect->SetDepthLargeTexture(mShadowLargeMap->GetTexture());

	Game::Instance()->GetMainRenderItemManager()->RenderShadow(&mLightViewMatrix, &mLightProjectionMatrix,&mLightLargeViewMatrix, &mLightLargeProjectionMatrix);

	mBlurRender->Render();
}

void ShadowRender::CreateTexture()
{
	HRESULT result;

	D3D11_TEXTURE2D_DESC sTexDesc;
	sTexDesc.Width = mWidth;
	sTexDesc.Height = mHeight;
	sTexDesc.MipLevels = 1;
	sTexDesc.ArraySize = 1;
	sTexDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
	sTexDesc.SampleDesc.Count = 1;
	sTexDesc.SampleDesc.Quality = 0;
	sTexDesc.Usage = D3D11_USAGE_DEFAULT;
	sTexDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	sTexDesc.CPUAccessFlags = 0;
	sTexDesc.MiscFlags = 0;

	result = mDevice->CreateTexture2D(&sTexDesc,NULL, &mTextureRender);
	if(FAILED(result))
	{
		return;
	}
}

ID3D11ShaderResourceView* ShadowRender::GetTexture()
{
	return mBlurRender->GetRenderTexture();//mTextureRessource;
}

DepthEffect* ShadowRender::GetDepthEffect()
{
	return mDepthEffect;
}

ShadowEffect* ShadowRender::GetShadowEffect()
{
	return mShadowEffect;
}